//Copyright 2010 Balazs Keri, Imre Keri
//
//This file is part of FireworksCreator.
//
//FireworksCreator is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//FireworksCreator is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with FireworksCreator.  If not, see <http://www.gnu.org/licenses/>.
//
#include <QGridLayout>
//#include <QHeaderView>
#include <QLabel>
#include <QPushButton>
//#include <QSpacerItem>
//#include <QStandardItemModel>
#include <QTextEdit>
#include <QToolButton>
#include <QVBoxLayout>
#include "attrevent.h"
#include "primitives.h"
#include "primitivegroup.h"
#include "pttimemarkview.h"
#include "pttimemarklistview.h"
#include "viewattributes.h"
//
PTTimeMarkListView::PTTimeMarkListView(QObject *p_parent)
:
   QObject(p_parent),
   particle_template(0),
   main_layout(new QGridLayout),
   //head_layout(new QVBoxLayout),
   add_button(new QPushButton(tr("add"))),
   //table_header(new QHeaderView(Qt::Horizontal)),
   status_widget(new QTextEdit())
{
   /*col_spacer[0]=new QSpacerItem(100,1,QSizePolicy::Fixed,QSizePolicy::Fixed);
   col_spacer[1]=new QSpacerItem(100,1,QSizePolicy::Fixed,QSizePolicy::Fixed);
   col_spacer[2]=new QSpacerItem(100,1,QSizePolicy::Fixed,QSizePolicy::Fixed);
   QStandardItemModel *header_model=new QStandardItemModel(1,3,table_header);
   header_model->setHeaderData(0,Qt::Horizontal,tr("Name","header"),Qt::DisplayRole);
   header_model->setHeaderData(1,Qt::Horizontal,tr("Time","header"),Qt::DisplayRole);
   header_model->setHeaderData(2,Qt::Horizontal,tr("Relative To","header"),Qt::DisplayRole);
   table_header->setModel(header_model);
   head_layout->addWidget(table_header);
   head_layout->addLayout(main_layout);
   head_layout->addStretch(1);
   head_layout->setContentsMargins(0,0,0,0);
   head_layout->setSpacing(0);
   main_layout->addItem(col_spacer[0],0,0);
   main_layout->addItem(col_spacer[1],0,1);
   main_layout->addItem(col_spacer[2],0,2);*/
   main_layout->setColumnStretch(0,1);
   main_layout->setColumnStretch(1,0);
   main_layout->setColumnStretch(2,0);
   main_layout->setHorizontalSpacing(2);
   QLabel *l=new QLabel(tr("Name","header"));
   l->setFrameStyle(QFrame::Panel|QFrame::Sunken);
   main_layout->addWidget(l,0,0);
   l=new QLabel(tr("Time","header"));
   l->setFrameStyle(QFrame::Panel|QFrame::Sunken);
   main_layout->addWidget(l,0,1);
   l=new QLabel(tr("Relative To","header"));
   l->setFrameStyle(QFrame::Panel|QFrame::Sunken);
   main_layout->addWidget(l,0,2);
   status_widget->setReadOnly(true);
   status_widget->setTextBackgroundColor(Qt::black);
   connect(add_button.data(),SIGNAL(clicked()),SLOT(on_add_button_clicked()));
   //connect(table_header,SIGNAL(sectionResized(int,int,int)),SLOT(on_table_header_sectionResized(int,int,int)));
   recreate_views();
   update_status();
}
PTTimeMarkListView::~PTTimeMarkListView()
{
   delete_views();
   //delete head_layout;
}
//
void PTTimeMarkListView::on_add_button_clicked()
{
   QString new_name;
   const unsigned int max_try=11111;
   unsigned int i=particle_template->time_marks.count();
   while(i<max_try)
   {
      new_name=tr("timemark%1").arg(i);
      if(!particle_template->time_marks.contains(new_name))
         break;
      ++i;
   }
   if(i>=max_try)
      return;
   //
   {
      QScopedPointer<PrimitiveGroup> group(new PrimitiveGroup(get_document()));
      Primitives::SelectPT *prim;
      group->set_description(tr("create timemark \"%2\" in particle template \"%1\"","commands").arg(particle_template->get_name()).arg(new_name));
      try
      {
         group->add_exec(prim=new Primitives::SelectPT(get_document(),particle_template,new Primitives::PTNewTimeMark(new_name)));
         group->finalize();
      }
      catch(UiError&)
      {
         return;
      }
      group.take();
   }
}
/*void PTTimeMarkListView::on_table_header_sectionResized(int logicalIndex,int oldSize,int newSize)
{
   Q_ASSERT(logicalIndex>=0 && logicalIndex<=2);
   col_spacer[logicalIndex]->setGeometry(QRect(0,0,newSize,1));
}*/
void PTTimeMarkListView::on_delete_button_clicked()
{
   const QToolButton *const sender_button=qobject_cast<const QToolButton*>(this->sender());
   QString tm_name=this->find_tm_from_delete_button(sender_button);
   if(!tm_name.isEmpty())
   {
      QScopedPointer<PrimitiveGroup> group(new PrimitiveGroup(this->get_document()));
      Primitives::SelectPT *prim;
      group->set_description(tr("delete timemark \"%2\" in particle template \"%1\"","commands").arg(particle_template->get_name()).arg(tm_name));
      try
      {
         group->add_exec(prim=new Primitives::SelectPT(this->get_document(),this->particle_template,new Primitives::PTRemTimeMark(tm_name)));
         group->finalize();
      }
      catch(UiError&)
      {
         return;
      }
      group.take();
   }
}
 //
void PTTimeMarkListView::handle_set_attr_group()
{
   if(get_attr_group())
   {
      const ViewAttributeType::ModelDataObject *const attr=ViewAttributeType::ModelDataObject::lookup(get_attr_group(),root_object);
      particle_template=qobject_cast<model::ParticleTemplate*>(attr->get_object());
   }
   else
   {
      particle_template=0;
   }
   recreate_views();
}
void PTTimeMarkListView::handle_attr_event(AttrEvent *p_ae)
{
   if(!this->get_document())
   {
      return;
   }
   switch(p_ae->get_type())
   {
   case AttrEvent::value_changed:
      {
         AttrValueChanged *avc=static_cast<AttrValueChanged*>(p_ae);
         if(avc->get_name()==root_object)
         {
            const ViewAttributeType::ModelDataObject *const attr=ViewAttributeType::ModelDataObject::lookup(this->get_attr_group(),root_object);
            this->particle_template=qobject_cast<model::ParticleTemplate*>(attr->get_object());
            this->recreate_views();
            this->update_status();
         }
      }
      break;
   }
}
void PTTimeMarkListView::handle_post_primitive(const Primitive &p_prim)
{
   using namespace Primitives;
   //
   if(!particle_template)
   {
      return;
   }
   //
   switch(p_prim.type)
   {
   case type_SelectPT:
      {
         const SelectPT &p=static_cast<const SelectPT&>(p_prim);
         if(p.get_pt_id()==particle_template->get_id())
         {
            switch(p.get_delegate().get_type())
            {
            case type_PTRenameTimeMark:
               {
                  const PTRenameTimeMark &rename=static_cast<const PTRenameTimeMark&>(p.get_delegate());
                  this->move_view(rename.get_other_name(),rename.get_current_name());
                  break;
               }
            case type_PTRemTimeMark:
               {
                  const PTRemTimeMark &rem=static_cast<const PTRemTimeMark&>(p.get_delegate());
                  if(p.was_undo())
                     this->insert_view(rem.get_time_mark_name());
                  else
                     this->delete_view(rem.get_time_mark_name());
                  break;
               }
            case type_PTNewTimeMark:
               {
                  const PTNewTimeMark &_new=static_cast<const PTNewTimeMark&>(p.get_delegate());
                  if(p.was_undo())
                     this->delete_view(_new.get_time_mark_name());
                  else
                     this->insert_view(_new.get_time_mark_name());
                  break;
               }
            default:
               break;
            }
            this->update_status();
         }
      }
      break;
   }
}
//
QLayout *PTTimeMarkListView::get_main_layout() const
{
   //return head_layout;
   return this->main_layout.data();
}
QWidget *PTTimeMarkListView::get_add_widget() const
{
   return this->add_button.data();
}
QWidget *PTTimeMarkListView::get_status_widget() const
{
   return this->status_widget.data();
}
//
void PTTimeMarkListView::recreate_views()
{
   delete_views();
   //
   if(particle_template)
   {
      this->ordered_tm_names=particle_template->time_marks.keys();
      qSort(this->ordered_tm_names.begin(),this->ordered_tm_names.end());
      for(int i=0;i<this->ordered_tm_names.count();++i)
      {
         append_tm_view(this->ordered_tm_names.at(i));
      }
   }
   //
   add_button->setEnabled(particle_template!=0);
}
void PTTimeMarkListView::append_tm_view(QString tm_name)
{
   PTTimeMarkView *const new_view=new PTTimeMarkView(this);
   QToolButton *const new_db=new QToolButton();
   views.append(new_view);
   delete_buttons.append(new_db);
   QSharedPointer<ViewAttributeGroup> new_ag(new ViewAttributeGroup(get_document()));
   ViewAttributeType::PTTimeMark *const new_attr=new ViewAttributeType::PTTimeMark(new_ag,root_object);
   new_attr->set_particle_template(particle_template,tm_name);
   new_view->set_attr_group(new_ag);
   new_db->setText(tr("-","button_symbol"));
   new_db->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Expanding);
   connect(new_db,SIGNAL(clicked()),SLOT(on_delete_button_clicked()));
   int row=main_layout->rowCount();
   main_layout->addWidget(new_view->get_name_widget(),row,0);
   main_layout->addWidget(new_view->get_time_widget(),row,1);
   main_layout->addWidget(new_view->get_other_widget(),row,2);
   main_layout->addWidget(new_db,row,3);
}
void PTTimeMarkListView::insert_view(const QString &tm_name)
{
   if(this->ordered_tm_names.contains(tm_name))
   {
      return;
   }
   //
   this->ordered_tm_names.append(tm_name);
   qSort(this->ordered_tm_names.begin(),this->ordered_tm_names.end());
   int i=this->ordered_tm_names.indexOf(tm_name);
   Q_ASSERT(i>=0);
   //
   PTTimeMarkView *const new_view=new PTTimeMarkView(this);
   QToolButton *const new_db=new QToolButton();
   this->views.insert(i,new_view);
   this->delete_buttons.insert(i,new_db);
   QSharedPointer<ViewAttributeGroup> new_ag(new ViewAttributeGroup(this->get_document()));
   ViewAttributeType::PTTimeMark *const new_attr=new ViewAttributeType::PTTimeMark(new_ag,root_object);
   new_attr->set_particle_template(particle_template,tm_name);
   new_view->set_attr_group(new_ag);
   new_db->setText(tr("-","button_symbol"));
   new_db->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Expanding);
   connect(new_db,SIGNAL(clicked()),SLOT(on_delete_button_clicked()));
   //
   this->repopulate_layout();
}
void PTTimeMarkListView::delete_view(const QString &tm_name)
{
   int i=this->ordered_tm_names.indexOf(tm_name);
   if(i<0)
      return;
   //
   this->main_layout->removeWidget(this->views[i]->get_name_widget());
   this->main_layout->removeWidget(this->views[i]->get_time_widget());
   this->main_layout->removeWidget(this->views[i]->get_other_widget());
   this->main_layout->removeWidget(this->delete_buttons[i]);
   delete this->views[i];
   delete this->delete_buttons[i];
   this->views.removeAt(i);
   this->delete_buttons.removeAt(i);
   this->ordered_tm_names.removeAt(i);
}
void PTTimeMarkListView::move_view(const QString &tm_name_old,const QString &tm_name_new)
{
   int i_old=this->ordered_tm_names.indexOf(tm_name_old);
   if(i_old<0)
   {
      this->insert_view(tm_name_new);
      return;
   }
   //
   this->ordered_tm_names.replace(i_old,tm_name_new);
   qSort(this->ordered_tm_names.begin(),this->ordered_tm_names.end());
   int i_new=this->ordered_tm_names.indexOf(tm_name_new);
   Q_ASSERT(i_new>=0);
   if(i_old!=i_new)
   {
      this->views.move(i_old,i_new);
      this->delete_buttons.move(i_old,i_new);
      /*PTTimeMarkView *const tmp_view=this->views[i_old];
      this->views.removeAt(i_old);
      this->views.insert(i_new,tmp_view);
      QPushButton *const tmp_button=this->delete_buttons[i_old];
      this->delete_buttons.removeAt(i_old);
      this->delete_buttons.insert(i_new,tmp_button);*/
      this->repopulate_layout();
   }
}
void PTTimeMarkListView::delete_views()
{
   for(int i=0;i<views.size();++i)
   {
      delete views[i];
      delete this->delete_buttons[i];
   }
   views.clear();
   this->delete_buttons.clear();
   this->ordered_tm_names.clear();
}
void PTTimeMarkListView::repopulate_layout()
{
   // is there a better way to do this?
   int rc=this->main_layout->rowCount();
   for(int i=rc-1;i>=1;--i)
   {
      this->main_layout->removeItem(this->main_layout->itemAtPosition(i,0));
      this->main_layout->removeItem(this->main_layout->itemAtPosition(i,1));
      this->main_layout->removeItem(this->main_layout->itemAtPosition(i,2));
      this->main_layout->removeItem(this->main_layout->itemAtPosition(i,3));
      /*const PTTimeMarkView *view=this->views.at(i);
      this->main_layout->removeWidget(view->get_name_widget());
      this->main_layout->removeWidget(view->get_time_widget());
      this->main_layout->removeWidget(view->get_other_widget());
      this->main_layout->removeWidget(this->delete_buttons.at(i));*/
   }
   for(int i=0;i<this->ordered_tm_names.count();++i)
   {
      const PTTimeMarkView *view=this->views.at(i);
      this->main_layout->addWidget(view->get_name_widget(),1+i,0);
      this->main_layout->addWidget(view->get_time_widget(),1+i,1);
      this->main_layout->addWidget(view->get_other_widget(),1+i,2);
      this->main_layout->addWidget(this->delete_buttons.at(i),1+i,3);
   }
}
QString PTTimeMarkListView::find_tm_from_delete_button(const QToolButton *p_delete_button) const
{
   int i=this->delete_buttons.indexOf(const_cast<QToolButton*>(p_delete_button));
   if(i>=0)
   {
      return this->ordered_tm_names[i];
   }
   return "";
}
void PTTimeMarkListView::update_status() const
{
   if(this->particle_template)
   {
      QStringList bad_tm;
      QString error_text;
      QStringList tm_sorted=this->particle_template->compute_time_mark_time_sort(error_text,bad_tm);
      if(error_text.isEmpty())
      {
         QString txt(QString("<center><u>%1</u>").arg(tr("In-time sequence of time marks:")));
         for(QStringList::const_iterator i=tm_sorted.begin();i!=tm_sorted.end();++i)
         {
            txt.append("<br/>");
            txt.append(*i);
         }
         txt.append("</center>");
         this->status_widget->setHtml(txt);
         this->status_widget->setTextColor(Qt::white);
      }
      else
      {
         QString txt(QString("<i>%1</i>").arg(tr("Error: %1").arg(error_text)));
         for(QStringList::const_iterator i=bad_tm.begin();i!=bad_tm.end();++i)
         {
            txt.append("<br/>");
            txt.append(*i);
         }
         this->status_widget->setHtml(txt);
         this->status_widget->setTextColor(Qt::red);
      }
   }
   else
   {
      this->status_widget->clear();
   }
}
